#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
#include <unicode/regex.h>
#include <unicode/ustream.h>
#include "KeywordCond.h"
#include "../CondError.h"
#include "../../utils/UnicodeStringComparer.h"

#define foreach BOOST_FOREACH

using namespace kc_sf;

// ---------------------------------------------------- //

KeywordCond::KeywordCond(
	Operator keyword_operator,
	const std::string &keyword,
	KeywordRange keyword_range )
{
	c_keyword_operator = keyword_operator;
	std::string keyword_copy = boost::trim_copy( keyword );
	boost::to_lower( keyword_copy );
	c_keyword = UnicodeString( keyword_copy.c_str() );
	c_keyword_range = keyword_range;
}

// ---------------------------------------------------- //

Logic::Symbol * KeywordCond::clone() const
{
	return new KeywordCond( *this );
}

// ---------------------------------------------------- //

bool KeywordCond::eval( const Message &msg )
{
	typedef std::pair <std::string, Header *> HeaderNamePair;
	c_matches = 0;

	switch( c_keyword_range )
	{
		case Body:
			foreach( BodyPart body_part, msg.mBodyParts )
			{
				eval( body_part.getDecodedText().toLower() );
			}
			break;

		case Headers:
			foreach( HeaderNamePair header_name, msg.mHeaders )
			{
				eval( header_name.second->getValue().toLower() );
			}
			break;

		case Subject:
		{
			UnicodeString subject = msg.mSubject;
			eval( subject.toLower() );
		}
			break;

		case Everywhere:
		{
			foreach( HeaderNamePair header_name, msg.mHeaders )
			{
				eval( header_name.second->getValue().toLower() );
			}
			foreach( BodyPart body_part, msg.mBodyParts )
			{
				eval( body_part.getDecodedText().toLower() );
			}
		}
			break;
		default:
			break;
	};

	if( c_matches == -1)
		c_matches = 0;

	return evalHowMany( c_matches );
}

// ---------------------------------------------------- //

void KeywordCond::eval( const UnicodeString &input )
{
	UnicodeStringComparer comparer( input );
	UnicodeStringComparer not_comparer( input );

	switch( c_keyword_operator )
	{
		case EqualMatch:
		case HasWord:
			comparer.contains( c_keyword );
			break;
		case NotEqualMatch:
		case NotHasWord:
			if( !not_comparer.contains( c_keyword ) )
				++ c_matches;
			break;
		case RegexMatch:
		case ContainsRegex:
			comparer.containsRegex( c_keyword );
			break;
		case NotRegexMatch:
		case NotContainsRegex:
			if( !comparer.containsRegex( c_keyword ) )
				++ c_matches;
			break;
		default:
			break;
	}

	c_matches += comparer.matchesNr();
}

